// -*- coding: utf-8 -*-

#include <list>
#include "hybrid_config.h"
#include "hybrid_solver.h"
#include "hybrid_reduction.h"
#include "hybrid_util.h"
#include "elisa/elisa_time.h"

USING_ELISA
using namespace v_bias;
using namespace v_blas;

//--------------------------------------------------------------------------
// class HybridReduction
//--------------------------------------------------------------------------

bool HybridReduction::reductionAlgorithm()
{
#ifdef HYBRID_PROFILE
	++numHybridReduction;
#endif

	// obtain the product of the VarImpl and (pre-computed) apriori bound
	ContConstraintRep *rep = m_constr->rep();

	Time & t = rep->getTime();
	TimeImpl *ti = dynamic_cast<TimeImpl *>(t.getImplementation().get());
	//const VNIntVec & aep = ti->domain().getAE();

	// TODO: 初期時間区間内での衝突判定を防ぐための工夫
	if (ti->domain().sup() < t.m_lb)
		return false;

	//FlowPipe fp = ti->domain();

	// 準備。
	VNIntVec iv(t.getInitValue());
	//VNInterval initT(VNInterval(inf(ti->domain().getTime()) + t.getExcess()));
	VNInterval initT(t.getInitTime() + t.getExcess());
	VNInterval endT0(ti->domain().inf() + v_bias::sup(t.getExcess()));
	VNInterval endT (ti->domain().sup());

	VnodePtr odeSolver(HybridSolver::getOdeSolver());

	// Tの下限までIVP-ODEを解く。
	if (sup(initT) != inf(endT0)) {
		
		// VNODEの準備。
		odeSolver->setHmax(sup(endT0) - inf(initT));
		odeSolver->setFirstEntry();
		odeSolver->setOneStep(vnodelp::off);

		odeSolver->integrate(initT, iv, endT0);
	}

	// VNODEの準備。
	odeSolver->setHmax(ti->domain().width());
	odeSolver->setFirstEntry();
	odeSolver->setOneStep(vnodelp::on);

	// IVP-ODEを解いてAEを得る。
	// 注意: oneStep(on) で解くと、最後のステップのAEしか得られない。
	//VNIntVec iv(ti->domain().getIV());
	//VNIntVec iv;
	//iv.assign(ia[0], ia[4])
	VNIntVec ae(iv);
	while (sup(initT) < inf(endT)) {
		odeSolver->integrate(initT, iv, endT);
		VNIntVec ae1 = odeSolver->getAprioriEncl();
		transform(ae.begin(), ae.end(), ae1.begin(), ae.begin(), vn::hull);
	}
	
	// ContVarにAEを設定する。
	const ContVarVec & cvv = rep->getContVars();
	for (int i(0), j(0); i < cvv.size(); ++i) {
		VarImplPtr vip = cvv[i]->getImplementation();
		ContVarImpl *cv = dynamic_cast<ContVarImpl *>(vip.get());

		Interval d(ae[i]);
		//cv->setAE(d);
		d.intersect(cv->domain());
		cv->setDomain(d);

		//j += cv->getOrder();
	}

	return true;
}
